#include "fibevent.h"

#include "IocpOperation.h"
#include "BaseIocpInitiator.h"
#include "IocpIoBaseInitiator.h"
#include "IocpFiber.h"

BaseIocpInitiator::BaseIocpInitiator(void)
	:m_operation(new IocpOperation())
	,m_result(0, wxtl::_win32_error(S_OK), false)
{
}


BaseIocpInitiator::~BaseIocpInitiator(void)
{
}

void BaseIocpInitiator::OnSwithcedContext()
{
	//throw any saved exceptions to client fiber, that we just switched to
	if(m_result.fail)
	{
		wxtl::_win32_error e(m_result.error);
		SetResult(IocpResult(0, wxtl::_win32_error(S_OK), false));
		throw (e);
	}
}

IocpOperation* BaseIocpInitiator::PrepareExOperation()
{
	*m_operation = IocpOperation(IocpOperation::Other, &IocpFiber::Current());
	return m_operation.get();
}

void BaseIocpInitiator::Switch()
{
	IocpFiber* fiber = (IocpFiber*)&IocpFiber::Current();
	fiber->SetCurrentInitiator(this);
	fiber->Y();
	OnSwithcedContext();
}

void BaseIocpInitiator::SetResult( const IocpResult& result )
{
	m_result = result;
}

void BaseIocpInitiator::OnOperationCompleted( const IocpResult& result, IocpOperation* operation )
{
	SetResult(result);
	Process(operation->m_destination, this);
}

void BaseIocpInitiator::Process( IocpFiber* destination, BaseIocpInitiator* initiator )
{
	if(!destination)
	{
		abort();
	}
	//try to post io request until successful post or  fiber ends
	do 
	{
		//SetBytes is called by ProcessIocpRequest() here
		destination->SetParent(&Fiber::Current());
		destination->Switch();

		if(destination->IsFinished() )
		{
			delete destination;
			break;
		}

		initiator = destination->GetCurrentInitiator();

	} while (!initiator->ProcessIocpRequest());
}
